/*
 * @(#)DateUtils.java 1.0 2013-11-5
 * 
 * Copyright(c) 2013, QuCai, Inc. All rights reserved.
 * 
 * This software is the confidential and proprietary information of QuCai, Inc.
 * You shall not disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into with QuCai.
 */
package com.zsc.common.web.util;

import org.apache.commons.lang.StringUtils;

import java.sql.Time;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Pattern;

/**
 * DateUtils.java是摇钱术直播服务系统的日期工具类。
 *
 * @author jason
 * @version 1.0 2013-11-5
 */
public class DateUtils extends org.apache.commons.lang.time.DateUtils {

    /**
     * yyyy-MM-dd HH:mm:ss格式化对象。
     */
    private static final DateFormat longDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * yyyyMMddHHmmss格式化对象。
     */
    private static final DateFormat yyyyMMddHHmmssDf = new SimpleDateFormat("yyyyMMddHHmmss");

    /**
     * yyyyMMdd格式化对象。
     */
    private static final DateFormat yyyyMMddDf = new SimpleDateFormat("yyyyMMdd");

    /**
     * yyyy-MM-dd格式化对象。
     */
    private static final DateFormat yyyyMMdd10Df = new SimpleDateFormat("yyyy-MM-dd");

    /**
     * HH:mm:ss格式化对象。
     */
    private static final DateFormat hhmmss8Df = new SimpleDateFormat("HH:mm:ss");

    /**
     * yyyy/MM/dd/HH/mm格式化对象。
     */
    private static final DateFormat yyyyMMddHHmmDf = new SimpleDateFormat("yyyy/MM/dd/HH/mm");

    /**
     * yyyy-MM-dd HH:mm格式化对象。
     */
    private static final DateFormat longTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");

    /**
     * yyyyMMddHHmm格式化对象。
     */
    private static final DateFormat longTime12Format = new SimpleDateFormat("yyyyMMddHHmm");

    /**
     * yyyy年MM月dd日格式化对象。
     */
    private static final DateFormat yyyyMMddChineseDf = new SimpleDateFormat("yyyy年MM月dd日");

    /**
     * yyyy/MM格式化对象。
     */
    private static final DateFormat yyyyMMDf = new SimpleDateFormat("yyyy/MM");

    /**
     * yyyy-MM-dd HH:mm:ss.SSS格式化对象。
     */
    private static final DateFormat longTimeMillisFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

    /**
     * HHmmssSSS格式化对象。
     */
    private static final DateFormat timeMillisFormat = new SimpleDateFormat("HHmmssSSS");

    /**
     * yyyyMMddHHmmssSSS格式化对象。
     */
    private static final DateFormat yyyyMMddHHmmssSSSDf = new SimpleDateFormat("yyyyMMddHHmmssSSS");

    /**
     * 日期间隔字符"-"。
     */
    private static final String separator = "-";

    /**
     * 以参数format日期格式，格式化日期对象。
     *
     * @param date   日期对象
     * @param format 日期格式
     * @return 格式化之后的日期字符串
     */
    public synchronized static String format(Date date, String format) {
        DateFormat sdf = new SimpleDateFormat(format);
        return date != null ? sdf.format(date) : null;
    }

    /**
     * 以yyyyMMddHHmmss格式，格式化日期对象。
     *
     * @param date 日期对象
     * @return yyyyMMddHHmmss格式的日期字符串
     */
    public synchronized static String format(Date date) {
        return date != null ? yyyyMMddHHmmssDf.format(date) : null;
    }

    /**
     * 以yyyy-MM-dd HH:mm:ss格式，格式化日期对象。
     *
     * @param date 日期对象
     * @return yyyy-MM-dd HH:mm:ss格式的日期字符串
     */
    public synchronized static String formatLongDate(Date date) {
        return date != null ? longDateFormat.format(date) : null;
    }

    /**
     * 以yyyyMMdd格式，格式化日期对象。
     *
     * @param date 日期对象
     * @return yyyyMMdd格式的日期字符串
     */
    public synchronized static String formatByyyyyMMdd(Date date) {
        return date != null ? yyyyMMddDf.format(date) : null;
    }

    /**
     * 以yyyy-MM-dd格式，格式化日期对象。
     *
     * @param date 日期对象
     * @return yyyy-MM-dd格式的日期字符串
     */
    public synchronized static String formatByyyyyMMdd10(Date date) {
        return date != null ? yyyyMMdd10Df.format(date) : null;
    }

    /**
     * 以HH:mm:ss格式，格式化时间对象。
     *
     * @param time 时间对象
     * @return HH:mm:ss格式的时间字符串
     */
    public synchronized static String formatByHHmmss8(Time time) {
        return time != null ? hhmmss8Df.format(time) : null;
    }

    /**
     * 以yyyy/MM/dd/HH/mm格式，格式化日期对象。
     *
     * @param date 日期对象
     * @return yyyy/MM/dd/HH/mm格式的日期字符串
     */
    public synchronized static String formatByyyyyMMdd16(Date date) {
        return date != null ? yyyyMMddHHmmDf.format(date) : null;
    }

    /**
     * 以yyyy-MM-dd HH:mm格式，格式化日期对象。
     *
     * @param date 日期对象
     * @return yyyy-MM-dd HH:mm格式的日期字符串
     */
    public synchronized static String formatLongTime(Date date) {
        return date != null ? longTimeFormat.format(date) : null;
    }

    /**
     * 以yyyyMMddHHmm格式，格式化日期对象。
     *
     * @param date 日期对象
     * @return yyyyMMddHHmm格式的日期字符串
     */
    public synchronized static String formatLongTime12(Date date) {
        return date != null ? longTime12Format.format(date) : null;
    }

    /**
     * 以yyyy年MM月dd日格式，格式化日期对象。
     *
     * @param date 日期对象
     * @return yyyy年MM月dd日格式的日期字符串
     */
    public synchronized static String formatByyyyyMMddChinese(Date date) {
        return date != null ? yyyyMMddChineseDf.format(date) : null;
    }

    /**
     * 以yyyy/MM格式，格式化日期对象。
     *
     * @param date 日期对象
     * @return yyyy/MM格式的日期字符串
     */
    public synchronized static String formatByyyyyMM(Date date) {
        return date != null ? yyyyMMDf.format(date) : null;
    }

    /**
     * 以yyyy-MM-dd HH:mm:ss.SSS格式，格式化日期对象。
     *
     * @param date 日期对象
     * @return yyyy-MM-dd HH:mm:ss.SSS格式的日期字符串
     */
    public synchronized static String formatByLongTimeMillis(Date date) {
        return date != null ? longTimeMillisFormat.format(date) : null;
    }

    /**
     * 以HHmmssSSS格式，格式化日期对象。
     *
     * @param date 日期对象
     * @return HHmmssSSS格式的日期字符串
     */
    public synchronized static String formatByTimeMillis(Date date) {
        return date != null ? timeMillisFormat.format(date) : null;
    }

    /**
     * 以yyyyMMddHHmmssSSS格式，格式化日期对象。
     *
     * @param date 日期对象
     * @return yyyyMMddHHmmssSSS格式的日期字符串
     */
    public synchronized static String formatByTimestampMillis(Date date) {
        return date != null ? yyyyMMddHHmmssSSSDf.format(date) : null;
    }

    /**
     * 以参数format日期格式，把字符串日期转化为日期对象。
     *
     * @param strDate 字符串日期
     * @param format  日期格式
     * @return 日期对象
     */
    public synchronized static Date parse(String strDate, String format) {
        DateFormat sdf = new SimpleDateFormat(format);
        try {
            return sdf.parse(strDate);
        } catch (ParseException e) {
            // 忽略;
        }
        return null;
    }

    /**
     * 以yyyy-MM-dd HH:mm:ss格式，把字符串日期转化为日期对象。
     *
     * @param strDate 字符串日期
     * @return 日期对象
     */
    public synchronized static Date parseLongDate(String strDate) {
        try {
            return longDateFormat.parse(strDate);
        } catch (ParseException e) {
            // 忽略;
        }
        return null;
    }

    /**
     * 以yyyyMMddhhmmss格式，把字符串日期转化为日期对象。
     *
     * @param strDate 字符串日期
     * @return 日期对象
     */
    public synchronized static Date parse(String strDate) {
        try {
            return yyyyMMddHHmmssDf.parse(strDate);
        } catch (ParseException e) {
            // 忽略;
        }
        return null;
    }

    /**
     * 以yyyyMMdd格式，把字符串日期转化为日期对象。
     *
     * @param strDate 字符串日期
     * @return 日期对象
     */
    public synchronized static Date parseByyyyyMMdd(String strDate) {
        try {
            return yyyyMMddDf.parse(strDate);
        } catch (ParseException e) {
            // 忽略;
        }
        return null;
    }

    /**
     * 以yyyy-MM-dd格式，把字符串日期转化为日期对象。
     *
     * @param strDate 字符串日期
     * @return 日期对象
     */
    public synchronized static Date parseByyyyyMMdd10(String strDate) {
        try {
            return yyyyMMdd10Df.parse(strDate);
        } catch (ParseException e) {
            // 忽略;
        }
        return null;
    }

    /**
     * 以HH:mm:ss格式，把字符串时间转化为时间对象。
     *
     * @param strTime 字符串时间
     * @return 时间对象
     */
    public synchronized static Date parseByHHmmss8(String strTime) {
        try {
            return hhmmss8Df.parse(strTime);
        } catch (ParseException e) {
            // 忽略;
        }
        return null;
    }

    /**
     * 以yyyy-MM-dd HH:mm格式，把字符串日期转化为日期对象。
     *
     * @param strDate 字符串日期
     * @return 日期对象
     */
    public synchronized static Date parseLongTime(String strDate) {
        try {
            return longTimeFormat.parse(strDate);
        } catch (ParseException e) {
            // 忽略;
        }
        return null;
    }

    /**
     * 以yyyyMMddHHmm格式，把字符串日期转化为日期对象。
     *
     * @param strDate 字符串日期
     * @return 日期对象
     */
    public synchronized static Date parseLongTime12(String strDate) {
        try {
            return longTime12Format.parse(strDate);
        } catch (ParseException e) {
            // 忽略;
        }
        return null;
    }

    /**
     * 以yyyy-MM-dd HH:mm:ss.SSS格式，把字符串日期转化为日期对象。
     *
     * @param strDate 字符串日期
     * @return 日期对象
     */
    public synchronized static Date parseLongTimeMillis(String strDate) {
        try {
            return longTimeMillisFormat.parse(strDate);
        } catch (ParseException e) {
            // 忽略;
        }
        return null;
    }

    /**
     * 确定参数时间点是不是HH:MM时间格式的24小时制时间点。
     *
     * @param time 时间点
     * @return true:是 false:不是
     */
    public static boolean is24HTime(String time) {
        if (StringUtils.isBlank(time)) {
            return false;
        }
        boolean is24HTime = Pattern.matches("^[0-2]{1}[0-9]{1}:[0-5]{1}[0-9]{1}$", time);
        if (is24HTime && time.startsWith("2")) {
            is24HTime = Pattern.matches("^2[0-3]{1}:[0-5]{1}[0-9]{1}$", time);
        }
        return is24HTime;
    }

    /**
     * 获取以HHMMSS格式的当前时间点。
     *
     * @return HHMMSS格式的当前时间点
     */
    public static int getCurrentTime() {
        Calendar currentCalendar = Calendar.getInstance();
        int currentHour = currentCalendar.get(Calendar.HOUR_OF_DAY);
        int currentMinute = currentCalendar.get(Calendar.MINUTE);
        int currentSecond = currentCalendar.get(Calendar.SECOND);
        return currentHour * 10000 + currentMinute * 100 + currentSecond;
    }

    /**
     * 获取以yyyyMMdd格式的当前日期。
     *
     * @return yyyyMMdd格式的当前日期
     */
    public static int getCurrentDate() {
        Calendar currentCalendar = Calendar.getInstance();
        int currentYear = currentCalendar.get(Calendar.YEAR);
        int currentMonth = currentCalendar.get(Calendar.MONTH) + 1;
        int currentDate = currentCalendar.get(Calendar.DATE);
        return currentYear * 10000 + currentMonth * 100 + currentDate;
    }

    /**
     * 根据日期，获取其所在的一年中的周期。
     *
     * @param date 日期
     * @return 周期
     */
    public static int getWeekOfYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int week = calendar.get(Calendar.WEEK_OF_YEAR);
        return week;
    }

    /**
     * 将yyyy-MM-dd格式的日期转换为yyyyMMdd格式的数字型日期。
     *
     * @return yyyyMMdd格式的数字型日期
     */
    public static int convertDate2Int(Date date) {
        if (date == null) {
            return 0;
        }
        String strDate = format(date, "yyyy-MM-dd");
        strDate = strDate.replaceAll(separator, "");
        return Integer.parseInt(strDate);
    }

    /**
     * 将yyyy-MM-dd格式的日期转换为yyyyMMdd格式的数字型日期。
     *
     * @return yyyyMMdd格式的数字型日期
     */
    public static int convertDate2Int(String date) {
        if (date == null) {
            return 0;
        }
        String strDate = date.replaceAll(separator, "");
        return Integer.parseInt(strDate);
    }

    /**
     * 将HH:mm:ss格式的时间转换为HHmmss格式的数字型时间。
     *
     * @return HHmmss格式的数字型时间
     */
    public static int convertTime2Int(Time time) {
        if (time == null) {
            return 0;
        }
        String strTime = format(time, "HH:mm:ss");
        strTime = strTime.replaceAll(":", "");
        return Integer.parseInt(strTime);
    }

    /**
     * 将HH:mm:ss格式的时间转换为HHmmss格式的数字型时间。
     *
     * @return HHmmss格式的数字型时间
     */
    public static int convertTime2Int(String time) {
        if (time == null) {
            return 0;
        }
        String strTime = time.trim().replaceAll(":", "");
        return Integer.parseInt(strTime);
    }

    /**
     * 将yyyyMMdd格式的数字型日期转换为yyyy-MM-dd格式的字符串型日期。
     *
     * @return yyyy-MM-dd格式的字符串型日期
     */
    public static String convertInt2Date(int date) {
        String strDate = String.valueOf(date);
        return convertInt2Date(strDate);
    }

    /**
     * 将yyyyMMdd格式的字符串型日期转换为yyyy-MM-dd格式的字符串型日期。
     *
     * @return yyyy-MM-dd格式的字符串型日期
     */
    public static String convertInt2Date(String strDate) {
        if (strDate.length() != 8) {
            return "";
        }
        strDate = strDate.substring(0, 4) + separator + strDate.substring(4, 6) + separator + strDate.substring(6);
        return strDate;
    }

    /**
     * 将yyyyMMdd格式的数字型日期转换为yyyy-MM-dd格式的字符串型日期。
     *
     * @return yyyy-MM-dd格式的字符串型日期
     */
    public static Date convertInt2Dateline(int date) {
        String strDate = convertInt2Date(date);
        if (strDate.length() != 10) {
            return null;
        }
        return java.sql.Date.valueOf(strDate);
    }

    /**
     * 将hhmmss格式的数字型时间转换为hh:mm:ss格式的时间对象。
     *
     * @return hh:mm:ss格式的时间对象
     */
    public static Time convertInt2Time(int time) {
        String strTime = String.valueOf(time);
        char timeChar = ':';
        int length = strTime.length();
        if (length == 6) {
            strTime = strTime.substring(0, 2) + timeChar + strTime.substring(2, 4) + timeChar + strTime.substring(4);
        } else if (length == 5) {
            strTime = strTime.substring(0, 1) + timeChar + strTime.substring(1, 3) + timeChar + strTime.substring(3);
        } else {
            return null;
        }
        return Time.valueOf(strTime);
    }

    /**
     * 根据指定的日期和指定的天数，获取以yyyy-MM-dd格式的指定日期。
     *
     * @param referenceDate
     * @param days          指定的天数
     * @return yyyy-MM-dd格式的指定日期
     */
    public static String getSpecifiedDate(String referenceDate, int days) {
        Calendar currentCalendar = Calendar.getInstance();
        currentCalendar.setTime(parseByyyyyMMdd10(referenceDate));
        currentCalendar.add(Calendar.DAY_OF_YEAR, days);
        return formatByyyyyMMdd10(currentCalendar.getTime());
    }

    /**
     * 根据当前日期和指定的天数，获取以yyyy-MM-dd格式的指定日期。
     *
     * @param days 指定的天数
     * @return yyyy-MM-dd格式的指定日期
     */
    public synchronized static String getSpecifiedDate(int days) {
        Calendar currentCalendar = Calendar.getInstance();
        currentCalendar.add(Calendar.DAY_OF_YEAR, days);
        return formatByyyyyMMdd10(currentCalendar.getTime());
    }

    /**
     * 根据当前日期和指定的分钟数，获取指定时间。
     *
     * @param minute 指定的分钟数
     * @return 指定时间
     */
    public static Date getSpecifiedTime(int minute) {
        return addMinutes(new Date(), minute);
    }

    /**
     * 根据当前日期和指定的秒数，获取指定时间。
     *
     * @param days 指定的秒数
     * @return 指定时间
     */
    public static Date getSpecifiedDateBySecond(int second) {
        return addSeconds(new Date(), second);
    }

    /**
     * <p>
     * Checks if two calendar objects are on the same week.
     * </p>
     * <p>
     * <p>
     * 2015-08-05 and 2015-08-07 would return true.
     * 2015-08-05 and 2015-08-12 would return false.
     * </p>
     *
     * @param cal1 the first calendar, not altered, not null
     * @param cal2 the second calendar, not altered, not null
     * @return true if they represent the same day
     * @throws IllegalArgumentException if either calendar is <code>null</code>
     */
    public static boolean isSameWeek(Calendar cal1, Calendar cal2) {
        if (cal1 == null || cal2 == null) {
            throw new IllegalArgumentException("The date must not be null");
        }
        return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR)
                && cal1.get(Calendar.WEEK_OF_YEAR) == cal2.get(Calendar.WEEK_OF_YEAR));
    }

    /**
     * <p>
     * Checks if two date objects are on the same week.
     * </p>
     * <p>
     * <p>
     * 2015-08-05 and 2015-08-07 would return true.
     * 2015-08-05 and 2015-08-12 would return false.
     * </p>
     *
     * @param date1 the first date, not altered, not null
     * @param date2 the second date, not altered, not null
     * @return true if they represent the same day
     * @throws IllegalArgumentException if either date is <code>null</code>
     */
    public static boolean isSameWeek(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
            throw new IllegalArgumentException("The date must not be null");
        }
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);
        return isSameWeek(cal1, cal2);
    }

    /**
     * 测试用
     */
    public static void main(String[] args) {
        Date now = new Date();
        System.out.println(Long.toHexString(DateUtils.addHours(now, 1).getTime() / 1000).toUpperCase());
    }
}